/***********************************************************************************************************************
*                                                                                                                      *
* SPLASH build system v0.1                                                                                             *
*                                                                                                                      *
* Copyright (c) 2013 Andrew D. Zonenberg                                                                               *
* All rights reserved.                                                                                                 *
*                                                                                                                      *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the     *
* following conditions are met:                                                                                        *
*                                                                                                                      *
*    * Redistributions of source code must retain the above copyright notice, this list of conditions, and the         *
*      following disclaimer.                                                                                           *
*                                                                                                                      *
*    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the       *
*      following disclaimer in the documentation and/or other materials provided with the distribution.                *
*                                                                                                                      *
*    * Neither the name of the author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                                                      *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES        *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR       *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE       *
* POSSIBILITY OF SUCH DAMAGE.                                                                                          *
*                                                                                                                      *
***********************************************************************************************************************/

#include "splashcore.h"

using namespace std;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

RTLILNetlistNode::RTLILNetlistNode(
	BuildGraph* graph,
	vector<HDLSourceNode*> sources,
	string name,
	string top_level,
	string device,
	FPGASynthesisFlagList flags,
	YosysCrowbarFPGAToolchain* toolchain)
	: HDLNetlistNode(graph, sources, name, top_level)
	, m_toolchain(toolchain)
	, m_device(device)
	, m_flags(flags)
{
	
}

RTLILNetlistNode::~RTLILNetlistNode()
{
	
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Factory method

RTLILNetlistNode* RTLILNetlistNode::CreateRTLILNetlistNode(
		BuildGraph* graph, 
		vector<string> sources,
		YosysCrowbarFPGAToolchain* toolchain,
		string name,
		string top_level,
		string device,
		FPGASynthesisFlagList flags)
{
	//Create source nodes for each of the source files
	vector<HDLSourceNode*> source_nodes;
	for(size_t i=0; i<sources.size(); i++)
	{	
		string fname = sources[i];
		if(DoesFileExist(fname))				//If it does not exist it's auto-generated and the path is already canonical
			fname = CanonicalizePath(fname);
		BuildGraphNode* node = graph->GetNodeForPath(fname, "generic");
		
		//Already exists? Sanity check and add it
		if(node != NULL)
		{
			HDLSourceNode* src = dynamic_cast<HDLSourceNode*>(node);
			if(src == NULL)
				FatalError("A node for \"%s\" already exists, but it's not HDL source\n", fname.c_str());
			source_nodes.push_back(src);
		}
		
		//No, create it
		else
		{
			//Determine what language the source file is
			if(fname.find(".vhdl") != fname.npos)
				FatalError("VHDLSourceNode class not implemented yet");
			else if(fname.find(".v") != fname.npos)
			{
				VerilogSourceNode* vnode = new VerilogSourceNode(graph, fname);
				graph->AddNodeWithPath(vnode, fname, "generic");
				source_nodes.push_back(vnode);
			}
			else
				FatalError("Unknown extension on source file %s (expected .v or .vhdl)\n", fname.c_str());
				
		}
	}
	
	//Create the netlist node
	RTLILNetlistNode* node = new RTLILNetlistNode(graph, source_nodes, name, top_level, device, flags, toolchain);
	graph->AddNode(node);
	
	//Done
	return node;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Accessors

string RTLILNetlistNode::GetOutputPath()
{
	string hash = GetHashCached();
	string outdir = m_graph->GetMetaDir() + "/" + hash;
	return outdir + "/" + m_name + ".rtlil";
}

string RTLILNetlistNode::GetDescription()
{
	char desc[1024];
	snprintf(desc, sizeof(desc), "RTLIL netlist %s", GetBasenameOfFile(GetOutputPath()).c_str());
	return string(desc);
}

string RTLILNetlistNode::GetBinaryPath()
{
	return GetOutputPath();
}

bool RTLILNetlistNode::GetFilteredOutput(std::vector<std::string>& output)
{
	static const char* whitelist[]=
	{
		"ERROR:",
		"error",
		"WARNING:",
		"warning"
	};
	
	static const char* blacklist[]=
	{
		"Number of errors"					//not really an error
	};
	
	return BuildGraphNode::GetFilteredOutput(
		output,
		whitelist,
		sizeof(whitelist)/sizeof(whitelist[0]),
		blacklist,
		sizeof(blacklist)/sizeof(blacklist[0])
		);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Building

string RTLILNetlistNode::GetHash()
{
	DebugPrintfHeading(5, "RTLILNetlistNode::GetHash() [node = \"%s\"]\n", m_name.c_str());
	string hashin = "";
	
	//Update our dependencies
	UpdateDependencies();

	//Add data at this node
	hashin += sha256(m_name);
	hashin += m_toolchain->GetHash();
	hashin += sha256(m_topLevel);
	hashin += sha256(m_device);
	hashin += m_toolchain->GetSynthesisFlagHash(m_flags);
		
	//Add data for our dependencies
	for(size_t i=0; i<m_dependencies.size(); i++)
		hashin += m_dependencies[i]->GetHashCached(); 
	
	return sha256(hashin);
}

void RTLILNetlistNode::Update(Cluster* cluster)
{
	//Rebuild all of our dependencies if necessary
	vector<ClusterJob*> deps;
	for(size_t i=0; i<m_dependencies.size(); i++)
	{		
		BuildGraphNode* node = m_dependencies[i];
		node->UpdateCached(cluster);
		if(node->GetBuildJob() != NULL)
			deps.push_back(node->GetBuildJob());
	}		
	
	//Save source file names
	vector<string> sources;
	for(size_t i=0; i<m_sources.size(); i++)
		sources.push_back(m_sources[i]->GetOutputPath());
	
	//Run the actual build
	m_job = m_toolchain->SynthesizeSourcesToUnplacedNetlist(
		sources,
		GetBinaryPath(),
		deps,
		m_topLevel,
		m_device,
		m_flags,
		cluster);
}
